<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>抛物线投掷动画</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        min-height: 100vh;
        background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
        color: white;
        padding: 20px;
        overflow: hidden;
      }

      .container {
        width: 100%;
        max-width: 900px;
        text-align: center;
      }

      h1 {
        margin-bottom: 20px;
        font-size: 2.5rem;
        text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
      }

      .description {
        margin-bottom: 30px;
        font-size: 1.1rem;
        line-height: 1.6;
        max-width: 700px;
        margin-left: auto;
        margin-right: auto;
      }

      .playground {
        position: relative;
        width: 100%;
        height: 500px;
        background-color: rgba(255, 255, 255, 0.1);
        border-radius: 12px;
        margin-bottom: 30px;
        overflow: hidden;
        box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
        border: 1px solid rgba(255, 255, 255, 0.2);
      }

      .draggable {
        position: absolute;
        width: 60px;
        height: 60px;
        background: linear-gradient(45deg, #ff416c, #ff4b2b);
        border-radius: 50%;
        cursor: grab;
        display: flex;
        align-items: center;
        justify-content: center;
        color: white;
        font-weight: bold;
        user-select: none;
        box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
        transition: transform 0.2s;
        z-index: 10;
      }

      .draggable:active {
        cursor: grabbing;
        transform: scale(1.1);
      }

      .controls {
        display: flex;
        gap: 15px;
        margin-bottom: 20px;
        flex-wrap: wrap;
        justify-content: center;
      }

      button {
        padding: 10px 20px;
        background: rgba(255, 255, 255, 0.2);
        border: none;
        border-radius: 50px;
        color: white;
        font-size: 1rem;
        cursor: pointer;
        transition: all 0.3s;
        backdrop-filter: blur(5px);
        border: 1px solid rgba(255, 255, 255, 0.3);
      }

      button:hover {
        background: rgba(255, 255, 255, 0.3);
        transform: translateY(-2px);
      }

      .stats {
        display: flex;
        justify-content: center;
        gap: 30px;
        margin-top: 20px;
        flex-wrap: wrap;
      }

      .stat-item {
        background: rgba(255, 255, 255, 0.1);
        padding: 15px 25px;
        border-radius: 10px;
        min-width: 150px;
        backdrop-filter: blur(5px);
        border: 1px solid rgba(255, 255, 255, 0.2);
      }

      .stat-value {
        font-size: 1.5rem;
        font-weight: bold;
        margin-top: 5px;
        color: #ffd700;
      }

      .trail {
        position: absolute;
        width: 8px;
        height: 8px;
        background-color: rgba(255, 215, 0, 0.7);
        border-radius: 50%;
        pointer-events: none;
      }

      .instructions {
        margin-top: 20px;
        font-style: italic;
        opacity: 0.8;
      }

      @media (max-width: 600px) {
        h1 {
          font-size: 1.8rem;
        }

        .playground {
          height: 400px;
        }

        .stats {
          flex-direction: column;
          align-items: center;
        }
      }
    </style>
  </head>
  <body>
    <div class="container">
      <h1>抛物线投掷动画模拟</h1>
      <p class="description">
        拖动小球并快速释放，观察在重力作用下的抛物线运动轨迹。小球会根据你的拖动速度产生不同的投掷效果。
      </p>

      <div class="controls">
        <button id="resetBtn">重置小球</button>
        <button id="toggleTrailBtn">切换轨迹显示</button>
        <button id="gravityBtn">切换重力方向</button>
      </div>

      <div class="playground" id="playground">
        <div class="draggable" id="ball">小球</div>
      </div>

      <div class="stats">
        <div class="stat-item">
          <div>水平速度</div>
          <div class="stat-value" id="velocityX">0 px/s</div>
        </div>
        <div class="stat-item">
          <div>垂直速度</div>
          <div class="stat-value" id="velocityY">0 px/s</div>
        </div>
        <div class="stat-item">
          <div>投掷次数</div>
          <div class="stat-value" id="throwCount">0</div>
        </div>
      </div>

      <p class="instructions">
        提示：尝试不同的拖动速度和方向，观察抛物线轨迹的变化
      </p>
    </div>

    <script>
      document.addEventListener("DOMContentLoaded", function () {
        const ball = document.getElementById("ball");
        const playground = document.getElementById("playground");
        const resetBtn = document.getElementById("resetBtn");
        const toggleTrailBtn = document.getElementById("toggleTrailBtn");
        const gravityBtn = document.getElementById("gravityBtn");
        const velocityXEl = document.getElementById("velocityX");
        const velocityYEl = document.getElementById("velocityY");
        const throwCountEl = document.getElementById("throwCount");

        // 物理参数
        let gravity = 0.5; // 重力加速度
        let damping = 0.8; // 碰撞阻尼系数
        let airResistance = 0.99; // 空气阻力系数
        let showTrail = true; // 是否显示轨迹

        // 状态变量
        let isDragging = false;
        let isThrown = false;
        let throwCount = 0;
        let velocityX = 0;
        let velocityY = 0;
        let lastX = 0;
        let lastY = 0;
        let lastTime = 0;
        let gravityDirection = 1; // 1表示向下，-1表示向上

        // 小球初始位置
        const initialPosition = {
          x: playground.offsetWidth / 2 - ball.offsetWidth / 2,
          y: playground.offsetHeight / 2 - ball.offsetHeight / 2,
        };

        // 设置小球初始位置
        ball.style.left = initialPosition.x + "px";
        ball.style.top = initialPosition.y + "px";

        // 鼠标/触摸事件处理
        ball.addEventListener("mousedown", startDrag);
        ball.addEventListener("touchstart", startDrag);

        document.addEventListener("mousemove", drag);
        document.addEventListener("touchmove", drag);

        document.addEventListener("mouseup", endDrag);
        document.addEventListener("touchend", endDrag);

        // 按钮事件
        resetBtn.addEventListener("click", resetBall);
        toggleTrailBtn.addEventListener("click", toggleTrail);
        gravityBtn.addEventListener("click", toggleGravity);

        // 开始拖动
        function startDrag(e) {
          e.preventDefault();
          isDragging = true;
          isThrown = false;
          ball.style.cursor = "grabbing";

          // 记录初始位置和时间
          lastX = e.clientX || e.touches[0].clientX;
          lastY = e.clientY || e.touches[0].clientY;
          lastTime = Date.now();
        }

        // 拖动中
        function drag(e) {
          if (!isDragging) return;

          e.preventDefault();
          const clientX = e.clientX || e.touches[0].clientX;
          const clientY = e.clientY || e.touches[0].clientY;

          // 计算小球新位置
          const rect = playground.getBoundingClientRect();
          let newX = parseInt(ball.style.left) + (clientX - lastX);
          let newY = parseInt(ball.style.top) + (clientY - lastY);

          // 限制小球在容器内
          newX = Math.max(
            0,
            Math.min(newX, playground.offsetWidth - ball.offsetWidth),
          );
          newY = Math.max(
            0,
            Math.min(newY, playground.offsetHeight - ball.offsetHeight),
          );

          ball.style.left = newX + "px";
          ball.style.top = newY + "px";

          // 计算速度（用于投掷）
          const currentTime = Date.now();
          const deltaTime = currentTime - lastTime;

          if (deltaTime > 0) {
            velocityX = ((clientX - lastX) / deltaTime) * 100;
            velocityY = ((clientY - lastY) / deltaTime) * 100;

            updateStats();
          }

          lastX = clientX;
          lastY = clientY;
          lastTime = currentTime;
        }

        // 结束拖动（投掷）
        function endDrag() {
          if (!isDragging) return;

          isDragging = false;
          isThrown = true;
          ball.style.cursor = "grab";

          // 增加投掷计数
          throwCount++;
          throwCountEl.textContent = throwCount;

          // 开始动画
          requestAnimationFrame(animate);
        }

        // 动画循环
        function animate() {
          if (!isThrown) return;

          // 应用重力
          velocityY += gravity * gravityDirection;

          // 应用空气阻力
          velocityX *= airResistance;
          velocityY *= airResistance;

          // 计算新位置
          let newX = parseInt(ball.style.left) + velocityX;
          let newY = parseInt(ball.style.top) + velocityY;

          // 边界碰撞检测
          if (newX <= 0 || newX >= playground.offsetWidth - ball.offsetWidth) {
            velocityX = -velocityX * damping; // 水平方向反弹
            newX = newX <= 0 ? 0 : playground.offsetWidth - ball.offsetWidth;
          }

          if (
            newY <= 0 ||
            newY >= playground.offsetHeight - ball.offsetHeight
          ) {
            velocityY = -velocityY * damping; // 垂直方向反弹
            newY = newY <= 0 ? 0 : playground.offsetHeight - ball.offsetHeight;

            // 如果速度很小，停止动画
            if (Math.abs(velocityY) < 0.5 && Math.abs(velocityX) < 0.5) {
              isThrown = false;
              velocityX = 0;
              velocityY = 0;
              updateStats();
              return;
            }
          }

          // 更新位置
          ball.style.left = newX + "px";
          ball.style.top = newY + "px";

          // 添加轨迹点
          if (showTrail) {
            addTrailPoint(
              newX + ball.offsetWidth / 2,
              newY + ball.offsetHeight / 2,
            );
          }

          updateStats();

          // 继续动画
          requestAnimationFrame(animate);
        }

        // 添加轨迹点
        function addTrailPoint(x, y) {
          const trail = document.createElement("div");
          trail.className = "trail";
          trail.style.left = x + "px";
          trail.style.top = y + "px";
          playground.appendChild(trail);

          // 3秒后淡出并移除轨迹点
          setTimeout(() => {
            trail.style.opacity = "0";
            trail.style.transition = "opacity 1s";
            setTimeout(() => {
              if (trail.parentNode) {
                trail.parentNode.removeChild(trail);
              }
            }, 1000);
          }, 3000);
        }

        // 更新统计数据
        function updateStats() {
          velocityXEl.textContent = velocityX.toFixed(1) + " px/s";
          velocityYEl.textContent = velocityY.toFixed(1) + " px/s";
        }

        // 重置小球
        function resetBall() {
          isThrown = false;
          velocityX = 0;
          velocityY = 0;

          ball.style.left = initialPosition.x + "px";
          ball.style.top = initialPosition.y + "px";

          // 清除所有轨迹点
          const trails = document.querySelectorAll(".trail");
          trails.forEach((trail) => trail.remove());

          updateStats();
        }

        // 切换轨迹显示
        function toggleTrail() {
          showTrail = !showTrail;
          toggleTrailBtn.textContent = showTrail ? "隐藏轨迹" : "显示轨迹";

          if (!showTrail) {
            const trails = document.querySelectorAll(".trail");
            trails.forEach((trail) => trail.remove());
          }
        }

        // 切换重力方向
        function toggleGravity() {
          gravityDirection = -gravityDirection;
          gravityBtn.textContent =
            gravityDirection === 1 ? "重力向下" : "重力向上";
        }
      });
    </script>
  </body>
</html>
